package com.jeesite.modules.dataScreen.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.jeesite.modules.dataScreen.dao.MonitoringDao;
import com.jeesite.modules.dataScreen.dao.TianbaoDao;
import com.jeesite.modules.dataScreen.dao.themedb.ThemeDbDao;
import com.jeesite.modules.dataScreen.domain.monitoring.PublicOpinionMonitoring;
import com.jeesite.modules.dataScreen.entity.Tianbao;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.NamedThreadLocal;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 填报列表查询
 */
@Service
@Slf4j
public class TianBaoService  extends ServiceImpl<TianbaoDao, Tianbao> {

    NamedThreadLocal<Map<String, String>> threadLocal = new NamedThreadLocal<>("tianbao");

    private static final String TBDW = "tbdw";
    private static final String UPDATE = "update";

    @Resource
    private ThemeDbDao themeDbDao;

    @Resource
    private ThreadPoolExecutor threadPoolExecutor;

    private final LoadingCache<String, String> loadingCache = CacheBuilder.newBuilder()
            // 设置并发级别为8，并发级别是指可以同时写缓存的线程数
            .concurrencyLevel(10)
            // 设置写缓存后过期时间
            .expireAfterWrite(60, TimeUnit.SECONDS)
            // 设置缓存容器的初始容量
            .initialCapacity(200)
            // 设置缓存最大容量,超过最大容量之后就会按照LRU最近虽少使用算法来移除缓存项
            .maximumSize(1000)
            // 设置要统计缓存的命中率
            .recordStats()
            //当获取缓存不存在时, 默认执行
            .build(new CacheLoader<String, String>() {
                @Override
                public String load(String key) {
                    Map<String, String> stringMap = get();
                    return getValue(key, stringMap.get(TBDW), stringMap.get(UPDATE));
                }

                @Override
                public Map<String, String> loadAll(Iterable<? extends String> keys) throws Exception {
                    int size = CollUtil.size(keys);
                    CountDownLatch countDownLatch = new CountDownLatch(size);

                    Map<String, String> stringMap = get();
                    String tbdw = stringMap.get(TBDW);
                    String update = stringMap.get(UPDATE);
                    Map<String, String> result = new HashMap<>();
                    for (String key : keys) {
                        threadPoolExecutor.execute(() -> {
                            try {
                                result.put(key, getValue(key, tbdw, update));
                            } catch (Exception e) {
                                e.fillInStackTrace();
                            } finally {
                                countDownLatch.countDown();
                            }
                        });
                    }
                    countDownLatch.await(Math.max(6, size / 2), TimeUnit.SECONDS);
                    return result;
                }

            });


    private String getValue(String key, String tbdw, String update) {
        Tianbao tianbao = themeDbDao.tianbaoLastValue(key, tbdw, update);
        log.info("填报缓存：{}，{}", key, JSONObject.toJSONString(tianbao));
        if (Objects.nonNull(tianbao) && StrUtil.isNotBlank(tianbao.getIndexValue())) {
            return tianbao.getIndexValue();
        }
        return "";
    }

    /**
     * 获取填报列表数据
     *
     * @param key    indexName
     * @param tbdw   tbdw填报单位
     * @param update update
     * @return indexValue
     */
    public String getIndexValue(String key, String tbdw, String update) {
        try {
            put(TBDW, tbdw);
            put(UPDATE, update);
            return loadingCache.get(key);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        } finally {
            clear();
        }
    }

    public String getIndexValue(String key) {
        return getIndexValue(key, null, null);
    }

    public Map<String, String> getAll(Collection<String> keys) {
        return getAll(keys, null, null);
    }

    public Map<String, String> getAll(Collection<String> keys, String tbdw, String update) {
        if (CollUtil.isEmpty(keys)) {
            return Collections.emptyMap();
        }
        try {
            put(TBDW, tbdw);
            put(UPDATE, update);
            return loadingCache.getAll(keys);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        } finally {
            clear();
        }
    }

    private void put(String key, String val) {
        Map<String, String> map = threadLocal.get();
        if (map == null) {
            map = new HashMap<>();
        }
        map.put(key, val);
        threadLocal.set(map);
    }

    private Map<String, String> get() {
        Map<String, String> stringMap = threadLocal.get();
        if (stringMap == null) {
            return Collections.emptyMap();
        }
        return stringMap;
    }

    private void clear() {
        threadLocal.remove();
    }



    public List<Tianbao> listByIndexNames(List<String> indexNames){
        LambdaQueryWrapper<Tianbao> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Tianbao::getIndexName, indexNames);
        return this.list(queryWrapper);
    }

}
